home *** CD-ROM | disk | FTP | other *** search
- /*
- * fsioFile.c --
- *
- * Routines for operations on files. A file handle is identified
- * by using the <major> field of the Fs_FileID for the domain index,
- * and the <minor> field for the file number.
- *
- * Copyright 1987 Regents of the University of California
- * All rights reserved.
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fsio/fsioFile.c,v 9.42 92/08/10 17:26:50 mgbaker Exp $ SPRITE (Berkeley)";
- #endif not lint
-
-
- #include <sprite.h>
- #include <fs.h>
- #include <fsutil.h>
- #include <fsconsist.h>
- #include <fsio.h>
- #include <fsioFile.h>
- #include <fslcl.h>
- #include <fsNameOps.h>
- #include <fscache.h>
- #include <fsprefix.h>
- #include <fsioLock.h>
- #include <fsdm.h>
- #include <fsrmt.h>
- #include <fsStat.h>
- #include <vm.h>
- #include <rpc.h>
- #include <recov.h>
-
- #include <stdio.h>
- #include <fsrecov.h>
- void IncVersionNumber _ARGS_((Fsio_FileIOHandle *handlePtr));
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_LocalFileHandleInit --
- *
- * Initialize a handle for a local file from its descriptor on disk.
- *
- * Results:
- * An error code from the read of the file descriptor off disk.
- *
- * Side effects:
- * Create and install a handle for the file. It is returned locked
- * and with its reference count incremented if SUCCESS is returned.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fsio_LocalFileHandleInit(fileIDPtr, name, descPtr, cantBlock, newHandlePtrPtr)
- Fs_FileID *fileIDPtr;
- char *name;
- Fsdm_FileDescriptor *descPtr;
- Boolean cantBlock;
- Fsio_FileIOHandle **newHandlePtrPtr;
- {
- register ReturnStatus status;
- register Fsio_FileIOHandle *handlePtr;
- register Fsdm_Domain *domainPtr;
- register Boolean found;
- Boolean allocated = FALSE;
-
- found = Fsutil_HandleInstall(fileIDPtr, sizeof(Fsio_FileIOHandle), name,
- cantBlock, (Fs_HandleHeader **)newHandlePtrPtr);
- if (found) {
- if ((*newHandlePtrPtr) == (Fsio_FileIOHandle *) NIL) {
- return FS_WOULD_BLOCK;
- }
- /*
- * All set.
- */
- if ((*newHandlePtrPtr)->descPtr == (Fsdm_FileDescriptor *)NIL) {
- panic("Fsio_LocalFileHandleInit, found handle with no descPtr\n");
- }
- return(SUCCESS);
- }
- status = SUCCESS;
- handlePtr = *newHandlePtrPtr;
- domainPtr = Fsdm_DomainFetch(fileIDPtr->major, FALSE);
- if (domainPtr == (Fsdm_Domain *)NIL) {
- Fsutil_HandleRelease(handlePtr, FALSE);
- Fsutil_HandleRemove(handlePtr);
- return(FS_DOMAIN_UNAVAILABLE);
- }
- if (descPtr == (Fsdm_FileDescriptor *) NIL) {
- /*
- * Get a hold of the disk file descriptor.
- */
- allocated = TRUE;
- descPtr = (Fsdm_FileDescriptor *)malloc(sizeof(Fsdm_FileDescriptor));
- status = Fsdm_FileDescFetch(domainPtr, fileIDPtr->minor, descPtr);
- if (status == FS_FILE_NOT_FOUND) {
- status = FS_FILE_REMOVED;
- }
- if ((status != SUCCESS) && (status != FS_FILE_REMOVED)) {
- printf(
- "Fsio_LocalFileHandleInit: Fsdm_FileDescFetch of %d failed 0x%x\n",
- fileIDPtr->minor, status);
- }
- }
- if ((status == SUCCESS) && !(descPtr->flags & FSDM_FD_ALLOC)) {
- status = FS_FILE_REMOVED;
- }
- if (status == SUCCESS) {
- Fscache_Attributes attr;
-
- handlePtr->descPtr = descPtr;
- handlePtr->flags = 0;
- /*
- * The use counts are updated when an I/O stream is opened on the file
- */
- handlePtr->use.ref = 0;
- handlePtr->use.write = 0;
- handlePtr->use.exec = 0;
-
- /*
- * Copy attributes that are cached in the handle.
- */
- attr.firstByte = descPtr->firstByte;
- attr.lastByte = descPtr->lastByte;
- attr.accessTime = descPtr->accessTime;
- attr.createTime = descPtr->createTime;
- attr.modifyTime = descPtr->dataModifyTime;
- attr.userType = descPtr->userType;
- attr.permissions = descPtr->permissions;
- attr.uid = descPtr->uid;
- attr.gid = descPtr->gid;
-
- Fscache_FileInfoInit(&handlePtr->cacheInfo,
- (Fs_HandleHeader *)handlePtr,
- descPtr->version, TRUE, &attr, domainPtr->backendPtr);
-
- Fsconsist_Init(&handlePtr->consist, (Fs_HandleHeader *)handlePtr);
- Fsio_LockInit(&handlePtr->lock);
- Fscache_ReadAheadInit(&handlePtr->readAhead);
-
- handlePtr->segPtr = (Vm_Segment *)NIL;
- }
- if (status != SUCCESS) {
- Fsutil_HandleRelease(handlePtr, FALSE);
- Fsutil_HandleRemove(handlePtr);
- if (allocated) {
- free((Address)descPtr);
- }
- *newHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
- } else {
- if (descPtr->fileType == FS_DIRECTORY) {
- fs_Stats.object.directory++;
- } else {
- fs_Stats.object.files++;
- }
- *newHandlePtrPtr = handlePtr;
- }
- Fsdm_DomainRelease(fileIDPtr->major);
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileSyncLockCleanup --
- *
- * This takes care of the dynamically allocated Sync_Lock's that
- * are embedded in a Fsio_FileIOHandle. This routine is
- * called when the file handle is being removed.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The locking statistics for this handle are combined with the
- * summary statistics for the lock types in the handle
- *
- *----------------------------------------------------------------------
- */
- void
- Fsio_FileSyncLockCleanup(handlePtr)
- Fsio_FileIOHandle *handlePtr;
- {
- Fsconsist_SyncLockCleanup(&handlePtr->consist);
- Fscache_InfoSyncLockCleanup(&handlePtr->cacheInfo);
- Fscache_ReadAheadSyncLockCleanup(&handlePtr->readAhead);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileNameOpen --
- *
- * This is called in two cases after name lookup on the server.
- * The first is when a client is opening the file from Fs_Open.
- * The second is when a lookup is done when getting/setting the
- * attributes of the files. In the open case this routine has
- * to set up Fsio_FileState that the client will use to complete
- * the setup of its stream, and create a server-side stream.
- * The handle should be locked upon entry, it remains locked upon return.
- *
- * Results:
- * SUCCESS.
- *
- * Side effects:
- * The major side effect of this routine is to invoke cache consistency
- * actions by other clients. This also does conflict checking, like
- * preventing writing if a file is being executed. Lastly, a shadow
- * stream is created here on the server to support migration.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fsio_FileNameOpen(handlePtr, openArgsPtr, openResultsPtr)
- register Fsio_FileIOHandle *handlePtr; /* A handle from FslclLookup.
- * Should be LOCKED upon entry,
- * Returned UNLOCKED. */
- Fs_OpenArgs *openArgsPtr; /* Standard open arguments */
- Fs_OpenResults *openResultsPtr;/* For returning ioFileID, streamID,
- * and Fsio_FileState */
- {
- Fsio_FileState *fileStatePtr;
- ReturnStatus status;
- register useFlags = openArgsPtr->useFlags;
- register clientID = openArgsPtr->clientID;
- register Fs_Stream *streamPtr;
-
- if ((useFlags & FS_WRITE) &&
- (handlePtr->descPtr->fileType == FS_DIRECTORY)) {
- status = FS_IS_DIRECTORY;
- goto exit;
- }
- if (handlePtr->descPtr->fileType == FS_DIRECTORY) {
- /*
- * Strip off execute permission that was used to allow access to
- * a directory.
- */
- useFlags &= ~FS_EXECUTE;
- }
- /*
- * Check against writing and executing at the same time. Fs_Open already
- * checks that useFlags doesn't contain both execute and write bits.
- */
- if (((useFlags & FS_EXECUTE) && (handlePtr->use.write > 0)) ||
- ((useFlags & (FS_WRITE|FS_CREATE)) && (handlePtr->use.exec > 0))) {
- status = FS_FILE_BUSY;
- goto exit;
- }
- /*
- * Add in read permission when executing a file so Fs_Read doesn't
- * foil page-ins later.
- */
- if ((useFlags & FS_EXECUTE) && (handlePtr->descPtr->fileType == FS_FILE)) {
- useFlags |= FS_READ;
- }
- /*
- * Set up the ioFileIDPtr so our caller can set/get attributes.
- */
- openResultsPtr->ioFileID = handlePtr->hdr.fileID;
- if (clientID != rpc_SpriteID) {
- openResultsPtr->ioFileID.type = FSIO_RMT_FILE_STREAM;
- }
- if (useFlags == 0) {
- /*
- * Only being called from the get/set attributes code.
- * Setting up the ioFileID is all that is needed.
- */
- status = SUCCESS;
- } else {
- /*
- * Called during an open. Update the summary use counts while
- * we still have the handle locked. Then unlock the handle and
- * do consistency call-backs. The handle is unlocked to allow
- * servicing of RPCs which are side effects
- * of the consistency requests (i.e. write-backs).
- */
- handlePtr->use.ref++;
- if (useFlags & FS_WRITE) {
- handlePtr->use.write++;
- IncVersionNumber(handlePtr);
- }
- if (useFlags & FS_EXECUTE) {
- handlePtr->use.exec++;
- }
- Fsutil_HandleUnlock(handlePtr);
- fileStatePtr = mnew(Fsio_FileState);
- status = Fsconsist_FileConsistency(handlePtr, clientID, useFlags,
- &fileStatePtr->cacheable, &fileStatePtr->openTimeStamp);
- if (status == SUCCESS) {
- /*
- * Copy cached attributes into the returned file state.
- */
- Fscache_GetCachedAttr(&handlePtr->cacheInfo, &fileStatePtr->version,
- &fileStatePtr->attr);
- /*
- * Return new usage flags to the client. This lets us strip
- * off the execute use flag (above, for directories) so
- * the client doesn't have to worry about it.
- */
- fileStatePtr->newUseFlags = useFlags;
- openResultsPtr->streamData = (ClientData)fileStatePtr;
- openResultsPtr->dataSize = sizeof(Fsio_FileState);
-
- if (handlePtr->descPtr->fileType == FS_DIRECTORY) {
- fileStatePtr->newUseFlags |= FS_DIR;
- }
-
- /*
- * Now set up a shadow stream on here on the server so we
- * can support shared offset even after migration.
- * Note: prefix handles get opened, but the stream is not used,
- * could dispose stream in FslclExport.
- */
-
- streamPtr = Fsio_StreamCreate(rpc_SpriteID, clientID,
- (Fs_HandleHeader *)handlePtr, useFlags, handlePtr->hdr.name);
- openResultsPtr->streamID = streamPtr->hdr.fileID;
-
- /*
- * Handles should be put into recovery box if 1) we're the server
- * for the object, and 2) either it's a remote request or we're
- * sharing the object with a client. XXX Right now I don't have
- * the sharing stuff in here!!! XXX
- */
- if (recov_Transparent && clientID != rpc_SpriteID) {
- /* Add file handle to recov box. */
- status = Fsrecov_AddHandle((Fs_HandleHeader *) handlePtr,
- (Fs_FileID *) NIL, clientID,
- useFlags, fileStatePtr->cacheable, TRUE);
- /* We'll have to do better than this! */
- if (status != SUCCESS) {
- panic(
- "Fsio_FileNameOpen: couldn't add handle to recov box.");
- }
- /*
- * Now add mapping between stream and ioHandle. We'll need to
- * handle error cases better!!
- */
- status = Fsrecov_AddHandle((Fs_HandleHeader *) streamPtr,
- (Fs_FileID *) &((Fs_HandleHeader *) handlePtr)->fileID,
- clientID, streamPtr->flags, streamPtr->offset, TRUE);
- if (status != SUCCESS) {
- panic(
- "Fsio_FileNameOpen: couldn't add stream to recov box.");
- }
- }
- Fsutil_HandleRelease(streamPtr, TRUE);
- return(SUCCESS);
- } else {
- /*
- * Consistency call-backs failed because the last writer
- * could not write back its copy of the file. We garbage
- * collect the client to retreat to a known bookkeeping point.
- */
- int ref, write, exec;
- printf("Consistency failed %x on <%d,%d>\n", status,
- handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor);
- Fsutil_HandleLock(handlePtr);
- Fsconsist_Kill(&handlePtr->consist, clientID,
- &ref, &write, &exec);
- handlePtr->use.ref -= ref;
- handlePtr->use.write -= write;
- handlePtr->use.exec -= exec;
- if ((handlePtr->use.ref < 0) || (handlePtr->use.write < 0) ||
- (handlePtr->use.exec < 0)) {
- panic("Fsio_FileNameOpen: client %d ref %d write %d exec %d\n",
- clientID, handlePtr->use.ref,
- handlePtr->use.write, handlePtr->use.exec);
- }
- free((Address)fileStatePtr);
- }
- }
- exit:
- Fsutil_HandleUnlock(handlePtr);
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileReopen --
- *
- * Reopen a file for use by a remote client. State is maintained in the
- * handle's client list about this open and whether or not the client
- * is caching.
- *
- * Results:
- * A failure code if the client was caching dirty blocks but lost
- * the race to re-open its file. (i.e. another client already opened
- * for writing.)
- *
- * Side effects:
- * The client use state for the client is brought into agreement
- * with what the client tells us. We do cache consistency too.
- *
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_FileReopen(hdrPtr, clientID, inData, outSizePtr, outDataPtr)
- Fs_HandleHeader *hdrPtr; /* IGNORED here on the server */
- int clientID; /* Client doing the reopen */
- ClientData inData; /* Fsio_FileReopenParams */
- int *outSizePtr; /* Size of returned data */
- ClientData *outDataPtr; /* Returned data */
- {
- register Fsio_FileReopenParams *reopenParamsPtr; /* Parameters from RPC */
- register Fsio_FileState *fileStatePtr; /* Results for RPC */
- Fsio_FileIOHandle *handlePtr; /* Local handle for file */
- register ReturnStatus status = SUCCESS; /* General return code */
- Fsdm_Domain *domainPtr;
- Fsrecov_HandleState recovInfo;
-
- *outDataPtr = (ClientData) NIL;
- *outSizePtr = 0;
- /*
- * Do initial setup for the reopen. We make sure that the disk
- * for the file is still around first, mark the client
- * as doing recovery, and fetch a local handle for the file.
- * NAME note: we have no name for the file after a re-open.
- */
- reopenParamsPtr = (Fsio_FileReopenParams *) inData;
-
- /*
- * If this is a fast restart, but we're still doing recovery
- * (fsrecov_FromBox is FALSE), we can look at recov box contents and
- * check them against what the client says is true.
- */
- if (recov_Transparent && fsrecov_AlreadyInit) {
- Fs_FileID fid;
-
- /*
- * The object won't be in the box if it has a 0 ref count and no
- * dirty blocks. It is
- * a bug currently that clients can send reopen requests for files
- * that aren't open (0 ref count), but for which they have cached
- * blocks. We'll fix this soon, I hope.
- */
- if (reopenParamsPtr->use.ref <= 0 &&
- !(reopenParamsPtr->flags & FSIO_HAVE_BLOCKS)) {
- goto FixClientBug;
- }
- fid = reopenParamsPtr->fileID;
- /* Get info from recov box. */
- status = Fsrecov_GetHandle(fid, clientID, &recovInfo, TRUE);
- if (status != SUCCESS) {
- panic("Fsio_FileReopen: couldn't get recov info for handle.");
- }
- /* Test it for sameness. */
- if ((recovInfo.fileID.major != reopenParamsPtr->fileID.major) ||
- (recovInfo.fileID.minor != reopenParamsPtr->fileID.minor)) {
- panic("Fsio_FileReopen: major or minor numbers disagree.");
- }
- if (recovInfo.use.ref != reopenParamsPtr->use.ref) {
- panic("Fsio_FileReopen: refs disagree.");
- }
- if (recovInfo.use.write != reopenParamsPtr->use.write) {
- panic("Fsio_FileReopen: write refs disagree.");
- }
- if (recovInfo.use.exec != reopenParamsPtr->use.exec) {
- panic("Fsio_FileReopen: exec refs disagree.");
- }
- if (recovInfo.info != reopenParamsPtr->version) {
- panic("Fsio_FileReopen: versions disagree.");
- }
- /*
- * If we're doing recovery from the box, then return what we
- * recovered from the box to the client that still is doing reopens.
- */
- if (fsrecov_FromBox) {
- handlePtr = (Fsio_FileIOHandle *) Fsutil_HandleFetch(&fid);
- fileStatePtr = mnew(Fsio_FileState);
- fileStatePtr->cacheable = reopenParamsPtr->flags & FSIO_HAVE_BLOCKS;
- fileStatePtr->version = recovInfo.info;
- fileStatePtr->attr = handlePtr->cacheInfo.attr;
- fileStatePtr->newUseFlags = 0; /* Not used in re-open */
- *outDataPtr = (ClientData) fileStatePtr;
- *outSizePtr = sizeof(Fsio_FileState);
- Fsutil_HandleRelease(handlePtr, TRUE);
-
- return SUCCESS;
- }
- }
-
- /*
- * If a client reopens a file with a 0 ref count, we make the reopen jump
- * here regardless of whether we're recovering from the recovery box
- * or not. The problem is that if the ref count is 0, we won't find the
- * object in the box! We'll fix the client side soon to prevent this.
- */
- FixClientBug:
- domainPtr = Fsdm_DomainFetch(reopenParamsPtr->fileID.major, FALSE);
- if (domainPtr == (Fsdm_Domain *)NIL) {
- return(FS_DOMAIN_UNAVAILABLE);
- }
- status = Fsio_LocalFileHandleInit(&reopenParamsPtr->fileID, (char *)NIL,
- (Fsdm_FileDescriptor *) NIL, FALSE, &handlePtr);
- if (status != SUCCESS) {
- goto reopenReturn;
- }
- /*
- * See if the client can still cache its dirty blocks.
- */
- if (reopenParamsPtr->flags & FSIO_HAVE_BLOCKS) {
- status = Fscache_CheckVersion(&handlePtr->cacheInfo,
- reopenParamsPtr->version, clientID);
- if (status != SUCCESS) {
- Fsutil_HandleRelease(handlePtr, TRUE);
- goto reopenReturn;
- }
- }
- /*
- * Update global use counts and version number.
- */
- Fsconsist_ReopenClient(handlePtr, clientID, reopenParamsPtr->use,
- reopenParamsPtr->flags & FSIO_HAVE_BLOCKS);
- if (reopenParamsPtr->use.write > 0) {
- IncVersionNumber(handlePtr);
- }
- /*
- * Now unlock the handle and do cache consistency call-backs.
- */
- fileStatePtr = mnew(Fsio_FileState);
- fileStatePtr->cacheable = reopenParamsPtr->flags & FSIO_HAVE_BLOCKS;
- Fsutil_HandleUnlock(handlePtr);
- status = Fsconsist_ReopenConsistency(handlePtr, clientID, reopenParamsPtr->use,
- reopenParamsPtr->flags & FS_SWAP,
- &fileStatePtr->cacheable, &fileStatePtr->openTimeStamp);
- if (status != SUCCESS) {
- /*
- * Consistency call-backs failed, probably due to disk-full.
- * We kill the client here as it will invalidate its handle
- * after this re-open fails.
- */
- int ref, write, exec;
- Fsutil_HandleLock(handlePtr);
- Fsconsist_Kill(&handlePtr->consist, clientID, &ref, &write, &exec);
- handlePtr->use.ref -= ref;
- handlePtr->use.write -= write;
- handlePtr->use.exec -= exec;
- if ((handlePtr->use.ref < 0) || (handlePtr->use.write < 0) ||
- (handlePtr->use.exec < 0)) {
- panic("Fsio_FileReopen: client %d ref %d write %d exec %d\n",
- clientID, handlePtr->use.ref,
- handlePtr->use.write, handlePtr->use.exec);
- }
- Fsutil_HandleUnlock(handlePtr);
- free((Address)fileStatePtr);
- } else {
- /*
- * Successful re-open here on the server. Copy cached attributes
- * into the returned file state.
- */
- Fscache_GetCachedAttr(&handlePtr->cacheInfo, &fileStatePtr->version,
- &fileStatePtr->attr);
- fileStatePtr->newUseFlags = 0; /* Not used in re-open */
- *outDataPtr = (ClientData) fileStatePtr;
- *outSizePtr = sizeof(Fsio_FileState);
-
- if (recov_Transparent && !fsrecov_AlreadyInit &&
- (reopenParamsPtr->use.ref > 0 ||
- (reopenParamsPtr->flags & FSIO_HAVE_BLOCKS))) {
- int useFlags = 0;
- Fs_FileID fid;
-
- fid = reopenParamsPtr->fileID;
- if (handlePtr->use.write) {
- useFlags |= FS_WRITE;
- }
- if (handlePtr->use.exec) {
- useFlags |= FS_EXECUTE;
- }
- /* Add file handle to recov box. */
- status = Fsrecov_AddHandle((Fs_HandleHeader *) handlePtr,
- (Fs_FileID *) NIL, clientID, useFlags,
- fileStatePtr->cacheable, (reopenParamsPtr->use.ref > 0));
- /* We'll have to do better than this! */
- if (status != SUCCESS) {
- panic("Fsio_FileReopen: couldn't add handle to recov box.");
- }
- /* Stream is added in stream reopen procedure. */
- }
- }
- Fsutil_HandleRelease(handlePtr, FALSE);
- reopenReturn:
- Fsdm_DomainRelease(reopenParamsPtr->fileID.major);
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileIoOpen --
- *
- * Set up a stream for a local disk file. This is called from Fs_Open to
- * complete the opening of a stream. By this time any cache consistency
- * actions have already been taken, and local use counts have been
- * incremented by Fsio_FileNameOpen.
- *
- * Results:
- * SUCCESS, unless there was an error installing the handle.
- *
- * Side effects:
- * Installs the handle for the file. This increments its refererence
- * count (different than the use count).
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_FileIoOpen(ioFileIDPtr, flagsPtr, clientID, streamData, name, ioHandlePtrPtr)
- Fs_FileID *ioFileIDPtr; /* I/O fileID from the name server */
- int *flagsPtr; /* Return only. The server returns
- * a modified useFlags in Fsio_FileState */
- int clientID; /* IGNORED */
- ClientData streamData; /* Fsio_FileState. */
- char *name; /* File name for error msgs */
- Fs_HandleHeader **ioHandlePtrPtr;/* Return - a handle set up for
- * I/O to a file, NIL if failure. */
- {
- register ReturnStatus status;
-
- status = Fsio_LocalFileHandleInit(ioFileIDPtr, name,
- (Fsdm_FileDescriptor *) NIL, FALSE,
- (Fsio_FileIOHandle **)ioHandlePtrPtr);
- if (status == SUCCESS) {
- /*
- * Return the new useFlags from the server. It has stripped off
- * execute permission for directories.
- */
- *flagsPtr = ( (Fsio_FileState *)streamData )->newUseFlags;
- Fsutil_HandleUnlock(*ioHandlePtrPtr);
- }
- free((Address)streamData);
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileClose --
- *
- * Close time processing for local files. We need to remove ourselves
- * from the list of clients of the file, decrement use counts, and
- * handle pending deletes. This returns either with one reference
- * to the handle released, or with the handle removed entirely.
- *
- * Results:
- * SUCCESS, FS_FILE_REMOVED, or an error code from the disk operation
- * on the file descriptor.
- *
- * Side effects:
- * Attributes cached on clients are propogated to the local handle.
- * Use counts in the client list are decremented. The handle's
- * use counts are decremented. If the file has been deleted, then
- * the file descriptor is so marked, other clients are told of
- * the delete, and the handle is removed entirely. Otherwise,
- * a reference on the handle is released.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Fsio_FileClose(streamPtr, clientID, procID, flags, dataSize, closeData)
- Fs_Stream *streamPtr; /* Stream to regular file */
- int clientID; /* Host ID of closer */
- Proc_PID procID; /* Process ID of closer */
- int flags; /* Flags from the stream being closed */
- int dataSize; /* Size of closeData */
- ClientData closeData; /* Ref. to Fscache_Attributes */
- {
- register Fsio_FileIOHandle *handlePtr =
- (Fsio_FileIOHandle *)streamPtr->ioHandlePtr;
- ReturnStatus status;
- Boolean wasCached = TRUE;
-
- /*
- * Update the client state to reflect the close by the client.
- */
-
- /*
- * This code is to track down a problem with clients sending bad
- * data.
- */
- if (flags & FS_EXECUTE) {
- List_Links *clientList = &(handlePtr->consist.clientList);
- Fsconsist_ClientInfo *clientPtr;
- LIST_FORALL(clientList, (List_Links *)clientPtr) {
- if (clientPtr->clientID == clientID) {
- if (clientPtr->use.exec==0) {
- printf("***ERROR***:Client %d: bad close on %s\n",
- clientID, Fsutil_HandleName(handlePtr));
- return(FAILURE);
- }
- }
- }
- }
- if (!Fsconsist_Close(&handlePtr->consist, clientID, flags, &wasCached)) {
- printf("Fsio_FileClose, client %d pid %x unknown for file <%d,%d>\n",
- clientID, procID, handlePtr->hdr.fileID.major,
- handlePtr->hdr.fileID.minor);
- Fsutil_HandleUnlock(handlePtr);
- return(FS_STALE_HANDLE);
- }
- if (wasCached && dataSize != 0) {
- /*
- * Update the server's attributes from ones cached on the client.
- */
- Fscache_UpdateAttrFromClient(clientID, &handlePtr->cacheInfo,
- (Fscache_Attributes *)closeData);
- (void)Fsdm_UpdateDescAttr(handlePtr, &handlePtr->cacheInfo.attr, -1);
- }
-
- Fsio_LockClose(&handlePtr->lock, &streamPtr->hdr.fileID);
-
- /*
- * Update use counts and handle pending deletions.
- */
- status = Fsio_FileCloseInt(handlePtr, 1, (flags & FS_WRITE) != 0,
- (flags & FS_EXECUTE) != 0,
- clientID, TRUE);
- if (status == FS_FILE_REMOVED) {
- /* XXX What is this about? XXX */
- if (recov_Transparent && clientID != rpc_SpriteID) {
- status = SUCCESS;
- if (Fsrecov_DeleteHandle((Fs_HandleHeader *) handlePtr, clientID,
- flags) != SUCCESS) {
- /* We'll have to do better than this! */
- panic("Fsio_FileClose: couldn't remove handle from recov box.");
- }
- if (Fsrecov_DeleteHandle((Fs_HandleHeader *) streamPtr, clientID,
- streamPtr->flags) != SUCCESS) {
- /* We'll have to do better than this! */
- panic("Fsio_FileClose: couldn't remove stream from recov box.");
- }
- }
- } else {
- status = SUCCESS;
- if (recov_Transparent && clientID != rpc_SpriteID) {
- if (Fsrecov_DeleteHandle((Fs_HandleHeader *) handlePtr, clientID,
- flags) != SUCCESS) {
- /* We'll have to do better than this! */
- panic("Fsio_FileClose: couldn't remove handle from recov box.");
- }
- if (Fsrecov_DeleteHandle((Fs_HandleHeader *) streamPtr, clientID,
- streamPtr->flags) != SUCCESS) {
- /* We'll have to do better than this! */
- panic("Fsio_FileClose: couldn't remove stream from recov box.");
- }
- }
- Fsutil_HandleRelease(handlePtr, TRUE);
- }
-
- return(status);
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Fsio_FileCloseInt --
- *
- * Close a file, handling pending deletions.
- * This is called from the regular close routine, from
- * the file client-kill cleanup routine, and from the
- * lookup routine that deletes file names.
- *
- * Results:
- * SUCCESS or FS_FILE_REMOVED.
- *
- * Side effects:
- * Adjusts use counts and does pending deletions. If the file is
- * deleted the handle can not be used anymore. Otherwise it
- * is left locked.
- *
- * ----------------------------------------------------------------------------
- *
- */
- ReturnStatus
- Fsio_FileCloseInt(handlePtr, ref, write, exec, clientID, callback)
- Fsio_FileIOHandle *handlePtr; /* File to clean up */
- int ref; /* Number of uses to remove */
- int write; /* Number of writers to remove */
- int exec; /* Number of executers to remove */
- int clientID; /* Closing, or crashed, client */
- Boolean callback; /* TRUE if we should call back to
- * the client and tell it about
- * the deletion. */
- {
- register ReturnStatus status;
- /*
- * Update the global/summary use counts for the file.
- */
- handlePtr->use.ref -= ref;
- handlePtr->use.write -= write;
- handlePtr->use.exec -= exec;
- if (handlePtr->use.ref < 0 || handlePtr->use.write < 0 ||
- handlePtr->use.exec < 0) {
- panic("Fsio_FileCloseInt <%d,%d> use %d, write %d, exec %d\n",
- handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
- handlePtr->use.ref, handlePtr->use.write, handlePtr->use.exec);
- }
-
- /*
- * Handle pending deletes
- * 0. Make sure it isn't being deleted already.
- * 1. Scan the client list and call-back to the last writer if
- * it is not the client doing the close. The handle gets
- * temporarily unlocked during the callback, so we are
- * are careful to ensure only one process does the delete.
- * 2. Mark the disk descriptor as deleted,
- * 3. Remove the file handle.
- * 4. Return FS_FILE_REMOVED so clients know to nuke their cache.
- */
- if ((handlePtr->use.ref == 0) &&
- (handlePtr->flags & FSIO_FILE_NAME_DELETED)) {
- if ((handlePtr->flags & FSIO_FILE_DESC_DELETED) == 0) {
- handlePtr->flags |= FSIO_FILE_DESC_DELETED;
- if (handlePtr->descPtr->fileType == FS_DIRECTORY) {
- fs_Stats.object.directory--;
- } else {
- fs_Stats.object.files--;
- }
- if (callback) {
- Fsconsist_ClientRemoveCallback(&handlePtr->consist, clientID);
- }
- (void)Fslcl_DeleteFileDesc(handlePtr);
- Fsio_FileSyncLockCleanup(handlePtr);
- if (callback) {
- Fsutil_HandleRelease(handlePtr, FALSE);
- }
- Fsutil_HandleRemove(handlePtr);
- } else {
- /*
- * The following printf is a mousetrap to verify that the
- * bug where Proc_ServerProcs leave files locked was fixed.
- * Remove it once we are positive the bug is fixed. JHH 11/5/90
- */
- printf(
- "Fsio_FileCloseInt: almost returned FS_FILE_REMOVED w/ handle locked\n");
- Fsutil_HandleUnlock(handlePtr);
- }
- status = FS_FILE_REMOVED;
- } else {
- status = SUCCESS;
- }
- return(status);
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Fsio_FileClientKill --
- *
- * Called when a client is assumed down. This cleans up the
- * cache consistency state associated with the client, and reflects
- * these changes in uses (i.e. less writers) in the handle's global
- * use counts.
- *
- *
- * Results:
- * SUCCESS.
- *
- * Side effects:
- * Removes the client list entry for the client and adjusts the
- * use counts on the file. This has to remove or unlock the handle.
- *
- * ----------------------------------------------------------------------------
- *
- */
- void
- Fsio_FileClientKill(hdrPtr, clientID)
- Fs_HandleHeader *hdrPtr; /* File to clean up */
- int clientID; /* Host assumed down */
- {
- Fsio_FileIOHandle *handlePtr = (Fsio_FileIOHandle *)hdrPtr;
- int refs, writes, execs;
- register ReturnStatus status;
- int flags = FS_READ;
-
- Fsconsist_IOClientKill(&handlePtr->consist.clientList, clientID,
- &refs, &writes, &execs);
- Fsio_LockClientKill(&handlePtr->lock, clientID);
-
- status = Fsio_FileCloseInt(handlePtr, refs, writes, execs, clientID, FALSE);
- while (refs > 0) {
- if (writes > 0) {
- flags |= FS_WRITE;
- }
- if (execs > 0) {
- flags |= FS_EXECUTE;
- }
- if (recov_Transparent && clientID != rpc_SpriteID) {
- if (Fsrecov_DeleteHandle((Fs_HandleHeader *) handlePtr, clientID,
- flags) != SUCCESS) {
- /* We'll have to do better than this! */
- panic("Fsio_FileClientKill: couldn't remove handle from recov box.");
- }
- }
- refs--;
- if (writes > 0) {
- writes--;
- }
- if (execs > 0) {
- execs--;
- }
- flags = FS_READ;
- }
- if (status != FS_FILE_REMOVED) {
- Fsutil_HandleUnlock(handlePtr);
- }
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Fsio_FileScavenge --
- *
- * Called periodically to see if this handle is still needed.
- *
- *
- * Results:
- * TRUE if it removed the handle.
- *
- * Side effects:
- * Removes the handle if their are no references to it and no
- * blocks in the cache for it. Otherwise it unlocks the handle
- * before returning.
- *
- * ----------------------------------------------------------------------------
- *
- */
- /*ARGSUSED*/
- Boolean
- Fsio_FileScavenge(hdrPtr)
- Fs_HandleHeader *hdrPtr; /* File to clean up */
- {
- register Fsio_FileIOHandle *handlePtr = (Fsio_FileIOHandle *)hdrPtr;
- register Boolean noUsers;
-
- /*
- * We can reclaim the handle if the following holds.
- * 0. The descriptor is not dirty.
- * 1. There are no active users of the file.
- * 2. The file is not undergoing deletion
- * (The deletion will remove the handle soon)
- * 3. There are no remote clients of the file. In particular,
- * the last writer might not be active, but we can't
- * nuke the handle until after it writes back.
- */
- noUsers = ((handlePtr->descPtr->flags & FSDM_FD_DIRTY) == 0) &&
- (handlePtr->use.ref == 0) &&
- ((handlePtr->flags & (FSIO_FILE_DESC_DELETED|
- FSIO_FILE_NAME_DELETED)) == 0) &&
- (Fsconsist_NumClients(&handlePtr->consist) == 0);
- if (noUsers && Fscache_OkToScavenge(&handlePtr->cacheInfo)) {
- register Boolean isDir;
- /*
- * Remove handles for files with no users and no blocks in cache.
- * We tell VM not to cache the segment associated with the file.
- * The "attempt remove" call unlocks the handle and then frees its
- * memory if there are no references to it lingering from the name
- * hash table.
- */
- Vm_FileChanged(&handlePtr->segPtr);
- isDir = (handlePtr->descPtr->fileType == FS_DIRECTORY);
- if (Fsutil_HandleAttemptRemove(hdrPtr)) {
- if (isDir) {
- fs_Stats.object.directory--;
- fs_Stats.object.dirFlushed++;
- } else {
- fs_Stats.object.files--;
- }
- return(TRUE);
- } else {
- return(FALSE);
- }
- } else {
- Fsutil_HandleUnlock(hdrPtr);
- return(FALSE);
- }
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Fsio_FileMigClose --
- *
- * Initiate migration of a FSIO_LCL_FILE_STREAM. There is no extra
- * state needed than already put together by Fsio_EncapStream. However,
- * we do release a low-level reference on the handle which is
- * re-obtained by FsFileDeencap. Other than that, we leave the
- * book-keeping alone, waiting to atomically switch references from
- * one client to the other at de-encapsulation time.
- *
- *
- * Results:
- * SUCCESS.
- *
- * Side effects:
- * Release a reference on the handle header.
- *
- * ----------------------------------------------------------------------------
- *
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_FileMigClose(hdrPtr, flags)
- Fs_HandleHeader *hdrPtr; /* File being encapsulated */
- int flags; /* Use flags from the stream */
- {
- panic( "Fsio_FileMigClose called\n");
- Fsutil_HandleRelease(hdrPtr, FALSE);
- return(SUCCESS);
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Fsio_FileMigOpen --
- *
- * Complete setup of a stream to a local file after migration to the
- * file server. Fsio_FileMigrate has done the work of shifting use
- * counts at the stream and I/O handle level. This routine has to
- * increment the low level I/O handle reference count to reflect
- * the existence of a new stream to the I/O handle.
- *
- * Results:
- * SUCCESS or FS_FILE_NOT_FOUND if the I/O handle can't be set up.
- *
- * Side effects:
- * Gains one reference to the I/O handle. Frees the client data.
- *
- * ----------------------------------------------------------------------------
- *
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_FileMigOpen(migInfoPtr, size, data, hdrPtrPtr)
- Fsio_MigInfo *migInfoPtr; /* Migration state */
- int size; /* sizeof(Fsio_FileState), IGNORED */
- ClientData data; /* referenced to Fsio_FileState */
- Fs_HandleHeader **hdrPtrPtr; /* Return - I/O handle for the file */
- {
- register ReturnStatus status;
- register Fsio_FileIOHandle *handlePtr;
-
- handlePtr = Fsutil_HandleFetchType(Fsio_FileIOHandle,
- &migInfoPtr->ioFileID);
- if (handlePtr == (Fsio_FileIOHandle *)NIL) {
- printf("Fsio_FileMigOpen, file <%d,%d> from client %d not found\n",
- migInfoPtr->ioFileID.major, migInfoPtr->ioFileID.minor,
- migInfoPtr->srcClientID);
- status = FS_FILE_NOT_FOUND;
- } else {
- Fsutil_HandleUnlock(handlePtr);
- *hdrPtrPtr = (Fs_HandleHeader *)handlePtr;
- status = SUCCESS;
- }
- free((Address)data);
- return(status);
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Fsio_FileMigrate --
- *
- * This takes care of transfering references from one client to the other.
- * Three things are done: cache consistency actions are taken to
- * reflect the movement of the client, file state is set up for use
- * on the client in the MigEnd procedure, and cross-network stream
- * sharing is detected. A useful side-effect of this routine is
- * to properly set the type in the ioFileID, either FSIO_LCL_FILE_STREAM
- * or FSIO_RMT_FILE_STREAM. In the latter case FsrmtFileMigrate
- * is called to do all the work.
- *
- * Results:
- * An error status if the I/O handle can't be set-up or if there
- * is a cache consistency failure. Otherwise SUCCESS is returned,
- * *flagsPtr may have the FS_RMT_SHARED bit set, and *sizePtr
- * and *dataPtr are set to reference Fsio_FileState.
- *
- * Side effects:
- * Sets the correct stream type on the ioFileID.
- * Shifts client references from the srcClient to the destClient.
- * Set up and return Fsio_FileState for use by the MigEnd routine.
- *
- * ----------------------------------------------------------------------------
- *
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_FileMigrate(migInfoPtr, dstClientID, flagsPtr, offsetPtr, sizePtr, dataPtr)
- Fsio_MigInfo *migInfoPtr; /* Migration state */
- int dstClientID; /* ID of target client */
- int *flagsPtr; /* In/Out Stream usage flags */
- int *offsetPtr; /* Return - correct stream offset */
- int *sizePtr; /* Return - sizeof(Fsio_FileState) */
- Address *dataPtr; /* Return - pointer to Fsio_FileState */
- {
- register Fsio_FileIOHandle *handlePtr;
- register Fsio_FileState *fileStatePtr;
- register ReturnStatus status;
- Boolean closeSrcClient;
-
- if (migInfoPtr->ioFileID.serverID != rpc_SpriteID) {
- /*
- * The file was local, which is why we were called, but is now remote.
- */
- migInfoPtr->ioFileID.type = FSIO_RMT_FILE_STREAM;
- return(FsrmtFileMigrate(migInfoPtr, dstClientID, flagsPtr, offsetPtr,
- sizePtr, dataPtr));
- }
- migInfoPtr->ioFileID.type = FSIO_LCL_FILE_STREAM;
- handlePtr = Fsutil_HandleFetchType(Fsio_FileIOHandle, &migInfoPtr->ioFileID);
- if (handlePtr == (Fsio_FileIOHandle *)NIL) {
- panic("Fsio_FileMigrate, no I/O handle");
- status = FS_STALE_HANDLE;
- } else {
-
- /*
- * At the stream level, add the new client to the set of clients
- * for the stream, and check for any cross-network stream sharing.
- * We only close the orignial client if the stream is unshared,
- * i.e. there are no references left there.
- */
- Fsio_StreamMigClient(migInfoPtr, dstClientID,
- (Fs_HandleHeader *)handlePtr, &closeSrcClient);
-
- /*
- * Adjust use counts on the I/O handle to reflect any new sharing.
- */
- Fsio_MigrateUseCounts(migInfoPtr->flags, closeSrcClient,
- &handlePtr->use);
-
- /*
- * Update the client list, and take any required cache consistency
- * actions. The handle returns unlocked from the consistency routine.
- */
- fileStatePtr = mnew(Fsio_FileState);
- Fsutil_HandleUnlock(handlePtr);
- status = Fsconsist_MigrateConsistency(handlePtr,
- migInfoPtr->srcClientID,
- dstClientID, migInfoPtr->flags, closeSrcClient,
- &fileStatePtr->cacheable, &fileStatePtr->openTimeStamp);
- /* Remove srcClient from recov box if it was its last handle ref. */
- if (recov_Transparent && closeSrcClient &&
- migInfoPtr->srcClientID != rpc_SpriteID) {
- if (Fsrecov_DeleteHandle((Fs_HandleHeader *) handlePtr,
- migInfoPtr->srcClientID, migInfoPtr->flags) != SUCCESS) {
- /* Do better than this. */
- panic("Fsio_FileMigrate: couldn't delete ioHandle from box.");
- }
- }
- /* Add the dstClient to box if this is a new stream for it. */
- if (recov_Transparent && (migInfoPtr->flags & FS_NEW_STREAM) &&
- dstClientID != rpc_SpriteID) {
- if (Fsrecov_AddHandle((Fs_HandleHeader *) handlePtr,
- (Fs_FileID *) NIL, dstClientID,
- migInfoPtr->flags & ~FS_NEW_STREAM,
- fileStatePtr->cacheable, TRUE) != SUCCESS) {
- /* Do better. */
- panic("Fsio_FileMigrate: couldn't add ioHandle to box.");
- }
- }
- if (status == SUCCESS) {
- Fscache_GetCachedAttr(&handlePtr->cacheInfo, &fileStatePtr->version,
- &fileStatePtr->attr);
- *sizePtr = sizeof(Fsio_FileState);
- *dataPtr = (Address)fileStatePtr;
- *flagsPtr = fileStatePtr->newUseFlags = migInfoPtr->flags;
- *offsetPtr = migInfoPtr->offset;
- } else {
- free((Address)fileStatePtr);
- }
- /*
- * We don't need this reference on the I/O handle, there is no change.
- */
- Fsutil_HandleRelease(handlePtr, FALSE);
- }
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileRead --
- *
- * Read from a file. This is a thin layer on top of the cache
- * read routine.
- *
- * Results:
- * The results of Fscache_Read.
- *
- * Side effects:
- * None, because Fscache_Read does most everything.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fsio_FileRead(streamPtr, readPtr, remoteWaitPtr, replyPtr)
- Fs_Stream *streamPtr; /* Open stream to the file. */
- Fs_IOParam *readPtr; /* Read parameter block. */
- Sync_RemoteWaiter *remoteWaitPtr; /* Process info for remote waiting */
- Fs_IOReply *replyPtr; /* Signal to return, if any,
- * plus the amount read. */
- {
- register Fsio_FileIOHandle *handlePtr =
- (Fsio_FileIOHandle *)streamPtr->ioHandlePtr;
- register ReturnStatus status;
- int savedOffset = readPtr->offset;
- int savedLength = readPtr->length;
-
- status = Fscache_Read(&handlePtr->cacheInfo, readPtr->flags,
- readPtr->buffer, readPtr->offset, &readPtr->length, remoteWaitPtr);
-
- if ((status == SUCCESS) || (readPtr->length > 0)) {
- (void)Fsdm_UpdateDescAttr(handlePtr, &handlePtr->cacheInfo.attr,
- FSDM_FD_ACCESSTIME_DIRTY);
- if (readPtr->flags & FS_SWAP) {
- int hostID = Proc_GetHostID(readPtr->procID);
- if (hostID == rpc_SpriteID) {
- /*
- * While page-ins on the file server come from its cache, we
- * inform the cache that these pages are good canidicates
- * for replacement.
- */
- Fscache_BlocksUnneeded(streamPtr, savedOffset, savedLength,
- FALSE);
- }
- }
-
- }
- replyPtr->length = readPtr->length;
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileWrite --
- *
- * Write to a disk file. This is a thin layer on top of the cache
- * write routine. Besides doing the write, this routine synchronizes
- * with read ahead on the file.
- *
- * Results:
- * The results of Fscache_Write.
- *
- * Side effects:
- * The handle is locked during the I/O.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fsio_FileWrite(streamPtr, writePtr, remoteWaitPtr, replyPtr)
- Fs_Stream *streamPtr; /* Open stream to the file. */
- Fs_IOParam *writePtr; /* Read parameter block */
- Sync_RemoteWaiter *remoteWaitPtr; /* Process info for remote waiting */
- Fs_IOReply *replyPtr; /* Signal to return, if any */
- {
- register Fsio_FileIOHandle *handlePtr =
- (Fsio_FileIOHandle *)streamPtr->ioHandlePtr;
- register ReturnStatus status;
- int savedOffset = writePtr->offset;
- int savedLength = writePtr->length;
-
- /*
- * Get a reference to the domain so it can't be dismounted during the I/O.
- * Then synchronize with read ahead before actually doing the write.
- */
- if (Fsdm_DomainFetch(handlePtr->hdr.fileID.major, FALSE) ==
- (Fsdm_Domain *)NIL) {
- return(FS_DOMAIN_UNAVAILABLE);
- }
- Fscache_WaitForReadAhead(&handlePtr->readAhead);
- status = Fscache_Write(&handlePtr->cacheInfo, writePtr->flags,
- writePtr->buffer, writePtr->offset,
- &writePtr->length, remoteWaitPtr);
- replyPtr->length = writePtr->length;
- if (status == SUCCESS) {
- if (replyPtr->length > 0) {
- (void)Fsdm_UpdateDescAttr(handlePtr, &handlePtr->cacheInfo.attr,
- FSDM_FD_MODTIME_DIRTY);
- }
- if (writePtr->flags & FS_SWAP) {
- int hostID = Proc_GetHostID(writePtr->procID);
- if (hostID == rpc_SpriteID) {
- /*
- * While page-outs on the file server go to its cache, we
- * inform the cache that these pages are good canidicates
- * for replacement.
- */
- Fscache_BlocksUnneeded(streamPtr, savedOffset, savedLength,
- FALSE);
- }
- }
- }
-
- Fscache_AllowReadAhead(&handlePtr->readAhead);
- Fsdm_DomainRelease(handlePtr->hdr.fileID.major);
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileBlockCopy --
- *
- * Copy the block from the source swap file to the destination swap file.
- *
- * NOTE: This routine does not call the routine that puts swap file blocks
- * on the front of the free list. This is because the general
- * mode of doing things is to fork which copies the swap file and
- * then exec which removes it. Thus we want the swap file to be
- * in the cache for the copy and we don't have to put the
- * destination files blocks on front of the lru list because it
- * is going to get removed real soon anyway.
- *
- * Results:
- * Error code if couldn't allocate disk space or didn't read a full
- * block.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_FileBlockCopy(srcHdrPtr, dstHdrPtr, blockNum)
- Fs_HandleHeader *srcHdrPtr; /* File to copy block from. */
- Fs_HandleHeader *dstHdrPtr; /* File to copy block to. */
- int blockNum; /* Block to copy. */
- {
- int offset;
- ReturnStatus status;
- Fscache_Block *cacheBlockPtr;
- int numBytes;
- register Fsio_FileIOHandle *srcHandlePtr =
- (Fsio_FileIOHandle *)srcHdrPtr;
- register Fsio_FileIOHandle *dstHandlePtr =
- (Fsio_FileIOHandle *)dstHdrPtr;
-
- /*
- * Look in the cache for the source block.
- */
- status = Fscache_BlockRead(&srcHandlePtr->cacheInfo, blockNum,
- &cacheBlockPtr, &numBytes, FSCACHE_DATA_BLOCK, FALSE);
- if (status != SUCCESS) {
- return(status);
- }
- if (numBytes != FS_BLOCK_SIZE) {
- if (numBytes != 0) {
- Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0,
- FSCACHE_CLEAR_READ_AHEAD);
- }
- return(VM_SHORT_READ);
- }
- /*
- * Write to the destination block.
- */
- numBytes = FS_BLOCK_SIZE;
- offset = blockNum * FS_BLOCK_SIZE;
- status = Fscache_Write(&dstHandlePtr->cacheInfo, FALSE,
- cacheBlockPtr->blockAddr, offset, &numBytes,
- (Sync_RemoteWaiter *) NIL);
- if (status == SUCCESS && numBytes != FS_BLOCK_SIZE) {
-
- status = VM_SHORT_WRITE;
- }
-
- Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
-
- srcHandlePtr->cacheInfo.attr.accessTime = Fsutil_TimeInSeconds();
- dstHandlePtr->cacheInfo.attr.modifyTime = Fsutil_TimeInSeconds();
- (void)Fsdm_UpdateDescAttr(srcHandlePtr, &srcHandlePtr->cacheInfo.attr,
- FSDM_FD_ACCESSTIME_DIRTY);
- (void)Fsdm_UpdateDescAttr(dstHandlePtr, &dstHandlePtr->cacheInfo.attr,
- FSDM_FD_MODTIME_DIRTY);
-
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileIOControl --
- *
- * IOControls for regular files. The handle should be locked up entry.
- * This handles byte swapping of its input and output buffers if
- * the clients byte ordering/padding is different.
- *
- * Results:
- * An error code from the command.
- *
- * Side effects:
- * Command dependent.
- *
- *----------------------------------------------------------------------
- */
-
- /*ARGSUSED*/
- ReturnStatus
- Fsio_FileIOControl(streamPtr, ioctlPtr, replyPtr)
- Fs_Stream *streamPtr; /* Stream to local file */
- Fs_IOCParam *ioctlPtr; /* I/O Control parameter block */
- Fs_IOReply *replyPtr; /* Return length and signal */
- {
- register Fsio_FileIOHandle *handlePtr =
- (Fsio_FileIOHandle *)streamPtr->ioHandlePtr;
- register ReturnStatus status = SUCCESS;
- Boolean unLock;
-
- Fsutil_HandleLock(handlePtr);
- unLock = TRUE;
- switch(ioctlPtr->command) {
- case IOC_REPOSITION:
- break;
- case IOC_GET_FLAGS:
- if ((ioctlPtr->outBufSize >= sizeof(int)) &&
- (ioctlPtr->outBuffer != (Address)NIL)) {
- *(int *)ioctlPtr->outBuffer = 0;
- }
- break;
- case IOC_SET_FLAGS:
- case IOC_SET_BITS:
- case IOC_CLEAR_BITS:
- break;
- #ifdef 0
- case IOC_MAP:
- #endif
- case IOC_TRUNCATE: {
- int arg; /* The truncation length for IOC_TRUNCATE,
- * The mapping flag for IOC_MAP. */
-
- if (ioctlPtr->inBufSize < sizeof(int)) {
- status = GEN_INVALID_ARG;
- } else if ((streamPtr->flags & FS_WRITE) == 0) {
- status = FS_NO_ACCESS;
- } else if (handlePtr->descPtr->fileType == FS_DIRECTORY) {
- status = FS_IS_DIRECTORY;
- } else if (ioctlPtr->format != mach_Format) {
- int outSize = sizeof(int);
- int inSize = sizeof(int);
- int fmtStatus;
- fmtStatus = Fmt_Convert("w", ioctlPtr->format, &inSize,
- ioctlPtr->inBuffer, mach_Format, &outSize,
- (Address) &arg);
- if (fmtStatus != 0) {
- printf("Format of ioctl failed <0x%x>\n", fmtStatus);
- status = GEN_INVALID_ARG;
- }
- if (outSize != sizeof(int)) {
- status = GEN_INVALID_ARG;
- }
- } else {
- arg = *(int *)ioctlPtr->inBuffer;
- }
- if (status == SUCCESS) {
- if (ioctlPtr->command == IOC_TRUNCATE) {
- if (arg < 0) {
- status = GEN_INVALID_ARG;
- } else {
- status = Fsio_FileTrunc(handlePtr, arg, 0);
- }
- } else {
- Fsutil_HandleUnlock(handlePtr);
- unLock = FALSE;
- status = Fsconsist_MappedConsistency(handlePtr,
- ioctlPtr->uid, arg);
- }
- }
- break;
- }
- case IOC_LOCK:
- case IOC_UNLOCK:
- status = Fsio_IocLock(&handlePtr->lock, ioctlPtr,
- &streamPtr->hdr.fileID);
- break;
- case IOC_NUM_READABLE: {
- /*
- * Return the number of bytes available to read. The top-level
- * IOControl routine has put the current stream offset in inBuffer.
- */
- int bytesAvailable;
- int streamOffset;
- int size;
-
- if (ioctlPtr->inBufSize != sizeof(int)) {
- status = GEN_INVALID_ARG;
- } else if (ioctlPtr->format != mach_Format) {
- int fmtStatus;
- int inSize;
- inSize = ioctlPtr->inBufSize;
- fmtStatus = Fmt_Convert("w", ioctlPtr->format, &inSize,
- ioctlPtr->inBuffer, mach_Format, &size,
- (Address) &streamOffset);
- if (fmtStatus != 0) {
- printf("Format of ioctl failed <0x%x>\n", fmtStatus);
- status = GEN_INVALID_ARG;
- }
- if (size != sizeof(int)) {
- status = GEN_INVALID_ARG;
- }
- } else {
- streamOffset = *(int *)ioctlPtr->inBuffer;
- }
- if (status == SUCCESS) {
- bytesAvailable = handlePtr->cacheInfo.attr.lastByte + 1 -
- streamOffset;
- if (ioctlPtr->outBufSize != sizeof(int)) {
- status = GEN_INVALID_ARG;
- } else if (ioctlPtr->format != mach_Format) {
- int fmtStatus;
- int inSize;
- inSize = sizeof(int);
- fmtStatus = Fmt_Convert("w", mach_Format, &inSize,
- (Address) &bytesAvailable, ioctlPtr->format,
- &size, ioctlPtr->outBuffer);
- if (fmtStatus != 0) {
- printf("Format of ioctl failed <0x%x>\n", fmtStatus);
- status = GEN_INVALID_ARG;
- }
- if (size != sizeof(int)) {
- status = GEN_INVALID_ARG;
- }
- } else {
- *(int *)ioctlPtr->outBuffer = bytesAvailable;
- }
- }
- break;
- }
- case IOC_SET_OWNER:
- case IOC_GET_OWNER:
- status = GEN_NOT_IMPLEMENTED;
- break;
- case IOC_PREFIX:
- break;
- case IOC_WRITE_BACK: {
- /*
- * Write out the cached data for the file.
- */
- Ioc_WriteBackArgs *argPtr = (Ioc_WriteBackArgs *)ioctlPtr->inBuffer;
- Fscache_FileInfo *cacheInfoPtr = &handlePtr->cacheInfo;
-
- if (ioctlPtr->inBufSize < sizeof(Ioc_WriteBackArgs)) {
- status = GEN_INVALID_ARG;
- } else {
- int firstBlock, lastBlock;
- int blocksSkipped;
- int flags = 0;
- Ioc_WriteBackArgs writeBack;
-
- if (ioctlPtr->format != mach_Format) {
- int fmtStatus;
- int size;
- size = ioctlPtr->inBufSize;
- fmtStatus = Fmt_Convert("w3", ioctlPtr->format, &size,
- ioctlPtr->inBuffer, mach_Format, &size,
- (Address) &writeBack);
- if (fmtStatus != 0) {
- printf("Format of ioctl failed <0x%x>\n", fmtStatus);
- status = GEN_INVALID_ARG;
- }
- if (size != sizeof(Ioc_WriteBackArgs)) {
- status = GEN_INVALID_ARG;
- }
- if (status != SUCCESS) {
- break;
- }
- argPtr = &writeBack;
- }
- if (argPtr->shouldBlock) {
- flags |= FSCACHE_FILE_WB_WAIT;
- }
- if (argPtr->firstByte > 0) {
- firstBlock = argPtr->firstByte / FS_BLOCK_SIZE;
- } else {
- firstBlock = 0;
- }
- if (argPtr->lastByte > 0) {
- lastBlock = argPtr->lastByte / FS_BLOCK_SIZE;
- } else {
- lastBlock = FSCACHE_LAST_BLOCK;
- }
- /*
- * Release the handle lock during the FileWriteBack to
- * avoid hanging up everyone who stumbles over the handle
- * during the writeback.
- */
- Fsutil_HandleUnlock(handlePtr);
- unLock = FALSE;
- status = Fscache_FileWriteBack(cacheInfoPtr, firstBlock,
- lastBlock, flags, &blocksSkipped);
- }
- break;
- }
- default:
- status = GEN_INVALID_ARG;
- break;
- }
- if (unLock) {
- Fsutil_HandleUnlock(handlePtr);
- }
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileTrunc --
- *
- * Shorten a file to length bytes. This calls routines to update
- * the cacheInfo and the fileDescriptor.
- *
- * Results:
- * Error status from Fsdm_FileTrunc.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Fsio_FileTrunc(handlePtr, size, flags)
- Fsio_FileIOHandle *handlePtr; /* File to truncate. */
- int size; /* Size to truncate the file to. */
- int flags; /* FSCACHE_TRUNC_DELETE */
- {
- ReturnStatus status;
-
- status = Fscache_Trunc(&handlePtr->cacheInfo, size, flags);
- if ((flags & FSCACHE_TRUNC_DELETE) == 0) {
- (void)Fsdm_UpdateDescAttr(handlePtr, &handlePtr->cacheInfo.attr,
- FSDM_FD_MODTIME_DIRTY);
- }
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileSelect --
- *
- * Always returns that file is readable and writable.
- *
- * Results:
- * SUCCESS - always returned.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_FileSelect(hdrPtr, waitPtr, readPtr, writePtr, exceptPtr)
- Fs_HandleHeader *hdrPtr; /* The handle of the file */
- Sync_RemoteWaiter *waitPtr; /* Process info for waiting */
- int *readPtr; /* Read bit */
- int *writePtr; /* Write bit */
- int *exceptPtr; /* Exception bit */
- {
- *exceptPtr = 0;
- return(SUCCESS);
- }
-
- /*
- *----------------------------------------------------------------------------
- *
- * IncVersionNumber --
- *
- * Increment the version number on file. This is done when a file
- * is opened for writing, and the version number is used by clients
- * to verify their caches. This must be called with the handle locked.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Version number incremented and the descriptor is pushed to disk.
- *
- *----------------------------------------------------------------------------
- *
- */
- void
- IncVersionNumber(handlePtr)
- Fsio_FileIOHandle *handlePtr;
- {
- Fsdm_FileDescriptor *descPtr;
-
- descPtr = handlePtr->descPtr;
- descPtr->version++;
- handlePtr->cacheInfo.version = descPtr->version;
- descPtr->flags |= FSDM_FD_VERSION_DIRTY;
- (void)Fsdm_FileDescStore(handlePtr, FALSE);
- Vm_FileChanged(&handlePtr->segPtr);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileRecovTestUseCount --
- *
- * For recovery testing, return the use count on the file's io handle.
- *
- * Results:
- * Use count.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- Fsio_FileRecovTestUseCount(handlePtr)
- Fsio_FileIOHandle *handlePtr;
- {
- return handlePtr->use.ref;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileRecovTestNumCacheBlocks --
- *
- * For recovery testing, return the number of blocks in the cache
- * for this file.
- *
- * Results:
- * Number of blocks.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- Fsio_FileRecovTestNumCacheBlocks(handlePtr)
- Fsio_FileIOHandle *handlePtr;
- {
- return handlePtr->cacheInfo.blocksInCache;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileRecovTestNumDirtyCacheBlocks --
- *
- * For recovery testing, return the number of dirty blocks in the cache
- * for this file.
- *
- * Results:
- * Number of dirty blocks.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- Fsio_FileRecovTestNumDirtyCacheBlocks(handlePtr)
- Fsio_FileIOHandle *handlePtr;
- {
- return handlePtr->cacheInfo.numDirtyBlocks;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_FileSetupHandle --
- *
- * Given a file recovery object, setup the necessary handle state for it.
- *
- * Results:
- * None.
- *
- * Side effects:
- * A handle is created in put in the handle table.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fsio_FileSetupHandle(recovInfoPtr)
- Fsrecov_HandleState *recovInfoPtr;
- {
- Fsdm_Domain *domainPtr;
- Fsio_FileIOHandle *handlePtr;
- int clientID;
- ReturnStatus status;
- int ref, write, exec;
- int useFlags;
- Fs_FileID fid;
-
- if (!recov_Transparent) {
- panic("Fsio_FileSetupHandle shouldn't have been called.");
- }
-
- fid = recovInfoPtr->fileID;
- clientID = fid.serverID;
- fid.serverID = rpc_SpriteID;
- domainPtr = Fsdm_DomainFetch(fid.major, FALSE);
- if (domainPtr == (Fsdm_Domain *) NIL) {
- #ifdef NOTDEF
- return FS_DOMAIN_UNAVAILABLE;
- #endif NOTDEF
- panic("Fsio_FileSetupHandle: domain unavailable.");
- }
- status = Fsio_LocalFileHandleInit(&fid, (char *) NIL,
- (Fsdm_FileDescriptor *) NIL, FALSE, &handlePtr);
- if (status != SUCCESS) {
- Fsdm_DomainRelease(fid.major);
- printf ("Status: 0x%x\n", status);
- panic("Fsio_FileSetupHandle: handle init failed.");
- }
- /* Cache consistency checks should be unnecessary. */
-
- /*
- * If necessary, I could use cacheable and use.write to say the
- * thing MAY have dirty blocks and do a consistency call back just in
- * case. To see if this is necessary, I need to see if write-back will
- * go ahead when processes are kicked on the client, or whether I need
- * to get the blocks via a consistency call. Test this!!! XXX
- */
-
- ref = recovInfoPtr->use.ref;
- write = recovInfoPtr->use.write;
- exec = recovInfoPtr->use.exec;
- if (ref > 0) {
- while (ref > 0) {
- useFlags = 0;
- if (write > 0) {
- useFlags |= FS_WRITE;
- }
- if (exec > 0) {
- useFlags |= FS_EXECUTE;
- }
- /* Client data is whether it's cacheable or not. */
- Fsconsist_UpdateFileConsistencyList(handlePtr, clientID, useFlags,
- recovInfoPtr->clientData);
- ref--;
- write--;
- exec--;
- }
- } else {
- /* Add to client list with 0 references. */
- Fsconsist_IOClientAdd(&(handlePtr->consist.clientList), clientID,
- recovInfoPtr->clientData);
- }
- handlePtr->use.ref += recovInfoPtr->use.ref;
- handlePtr->use.write += recovInfoPtr->use.write;
- handlePtr->use.exec += recovInfoPtr->use.exec;
- if (handlePtr->descPtr->version != recovInfoPtr->info) {
- panic("Fsio_FileSetupHandle: version on file is wrong.\n");
- }
- /*
- * Successful re-open here on the server. Copy cached attributes
- * into the returned file state.
- */
- Fsutil_HandleRelease(handlePtr, TRUE);
- Fsdm_DomainRelease(fid.major);
-
- return SUCCESS;
- }
-